package org.smartjava.concurrent.juc.queue;

import org.smartjava.util.PrintUtil;
import org.smartjava.util.ThreadUtil;

import java.util.concurrent.DelayQueue;
import java.util.concurrent.Delayed;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.locks.ReentrantLock;

public class DelayQueueExample {
    public static void main(String[] args) {
        DelayQueue<DelayData> delayQueue = new DelayQueue();
        for (long i = 0; i < 100; i++) {
            DelayData delayData = new DelayData(i, 10000 - 100 * i);
            delayQueue.add(delayData);
            delayQueue.offer(delayData);
        }

        ReentrantLock look = new ReentrantLock();
        for (int i = 0; i < 4; i++) {
            new Thread(() -> {
                look.lock();
                try {
                    while (!delayQueue.isEmpty()) {
                        PrintUtil.print(ThreadUtil.threadName(), ":", delayQueue.take());
                    }
                } catch (InterruptedException e) {
                    throw new RuntimeException(e);
                } finally {
                    look.unlock();
                }
            }, "T" + i).start();
        }
    }
}

class DelayData implements Delayed {

    private Long data;

    @Override
    public String toString() {
        return "DelayData{" +
                "data=" + data +
                ", time=" + time +
                '}';
    }

    private long start = System.currentTimeMillis();

    private long time;

    DelayData(Long data, long time) {
        this.data = data;
        this.time = time;
    }

    public Long getData() {
        return data;
    }

    @Override
    public long getDelay(TimeUnit unit) {
        return unit.convert(start + time - System.currentTimeMillis(), TimeUnit.MILLISECONDS);
    }

    @Override
    public int compareTo(Delayed o) {
        return (int) (this.getDelay(TimeUnit.MILLISECONDS) - o.getDelay(TimeUnit.MILLISECONDS));
    }

}
